package com.stars.easyms.datasource;

import org.springframework.lang.NonNull;

import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>className: EasyMsDataSourceSet</p>
 * <p>description: 存放EasyMsDataSource的set集合</p>
 *
 * @author guoguifang
 * @version 1.2.1
 * @date 2019-05-19 22:59
 */
public final class EasyMsDataSourceSet extends LinkedHashSet<EasyMsDataSource> {

    private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    EasyMsDataSourceSet() {
        super();
    }

    private EasyMsDataSourceSet(Collection<? extends EasyMsDataSource> c) {
        super(Math.max(2 * c.size(), 11));
        addAllEasyMsDataSources(c);
    }

    @Override
    public boolean add(EasyMsDataSource e) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean addAll(Collection<? extends EasyMsDataSource> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean remove(Object o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeIf(Predicate<? super EasyMsDataSource> filter) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Iterator<EasyMsDataSource> iterator() {
        return new EasyMsDataSourceIterator(super.iterator());
    }

    public EasyMsDataSource get(int index) {
        readWriteLock.readLock().lock();
        try {
            int size = size();
            if (index < 0 || index >= size) {
                throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
            }
            if (index == 0) {
                Optional<EasyMsDataSource> optional = stream().findFirst();
                if (optional.isPresent()) {
                    return optional.get();
                }
                throw new NoSuchElementException("First EasyMsDataSource instance is null!");
            }
            return this.toArray(new EasyMsDataSource[size])[index];
        } finally {
            readWriteLock.readLock().unlock();
        }
    }

    void addEasyMsDataSource(EasyMsDataSource e) {
        readWriteLock.writeLock().lock();
        try {
            super.add(e);
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    void addAllEasyMsDataSources(Collection<? extends EasyMsDataSource> c) {
        readWriteLock.writeLock().lock();
        try {
            c.forEach(this::addEasyMsDataSource);
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    /**
     * EasyMsDataSourceSet不开放删除，如果需要删除则新建一个EasyMsDataSourceSet对象
     *
     * @param e 需删除的元素
     * @return 如果删除完成后返回一个新的集合，若未删除则返回原对象
     */
    EasyMsDataSourceSet removeEasyMsDataSource(EasyMsDataSource e) {
        if (e != null) {
            readWriteLock.writeLock().lock();
            try {
                if (this.contains(e)) {
                    return this.stream().filter(easyMsDataSource -> !easyMsDataSource.equals(e)).collect(Collectors.toCollection(EasyMsDataSourceSet::new));
                }
            } finally {
                readWriteLock.writeLock().unlock();
            }
        }
        return this;
    }

    /**
     * EasyMsDataSourceSet不开放删除，如果需要删除则新建一个EasyMsDataSourceSet对象
     *
     * @param c 需删除的元素集合
     * @return 如果删除完成后返回一个新的集合，若未删除则返回原对象
     */
    EasyMsDataSourceSet removeAllEasyMsDataSources(@NonNull Collection<? extends EasyMsDataSource> c) {
        if (!c.isEmpty()) {
            readWriteLock.writeLock().lock();
            try {
                Set<EasyMsDataSource> resultSet = new LinkedHashSet<>(this);
                c.forEach(resultSet::remove);
                return new EasyMsDataSourceSet(resultSet);
            } finally {
                readWriteLock.writeLock().unlock();
            }
        }
        return this;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        EasyMsDataSourceSet easyMsDataSourceSet = (EasyMsDataSourceSet) obj;
        return easyMsDataSourceSet.size() == this.size() && easyMsDataSourceSet.containsAll(this);
    }

    @Override
    public int hashCode() {
        int result = 41;
        for (EasyMsDataSource easyMsDataSource : this) {
            result += 41 * easyMsDataSource.hashCode();
        }
        return result;
    }

    private class EasyMsDataSourceIterator implements Iterator<EasyMsDataSource> {

        private Iterator<EasyMsDataSource> iterator;

        private EasyMsDataSourceIterator(Iterator<EasyMsDataSource> iterator) {
            this.iterator = iterator;
        }

        @Override
        public boolean hasNext() {
            return this.iterator.hasNext();
        }

        @Override
        public EasyMsDataSource next() {
            return this.iterator.next();
        }
    }
}